package pogvue.datamodel;


import java.util.*;
import java.awt.event.*;
import pogvue.gui.hub.*;
import pogvue.gui.event.*;
import pogvue.gui.*;

public class GFFFragment extends GFF implements ActionListener {
    Vector frags;
    String type;

    Vector threads = null;

    Controller c;
    AlignViewport av;

    public GFFFragment(String name, String sequence, int start, int end,String type) {
	super(name,sequence,start,end);

	// Start end coords are in global chromosome coords

	this.length = end-start+1;

	frags = new Vector();
	this.type = type;

    }

    public void setAlignViewport(AlignViewport av) {
	this.av = av;

	if (av.getController() != null) {
	  setController(av.getController());
	}
    }

    public void setController(Controller c) {
	this.c = c;

    }

    public String getType() {
	return type;
    }
    public Vector<SequenceFeature> getFeatures() {
    	//return feat;
	// SHould this exist in a fragment setup
	return null;
    }
    
    // This decides a renderer somewhere - not sure quite why
    public Hashtable getScores() {
	return null;
    }
    public SequenceFeature getFeatureAt(int coord) {
	
	// This call needs to be sorted out at a higher level - called from AlignmentPanel
	return null;
	
    }

  public void getFeatureRegion(int tmpstart, int tmpend) {
    //System.out.println("Getting features " + tmpstart + " " + tmpend);
    
    // Check all the regions to see if we're covered
    
    Fragment found = null;
    
    for (int i = 0; i < frags.size(); i++) {
      Fragment f = (Fragment)frags.elementAt(i);
      if (f.getStart() <= tmpstart &&
	  f.getEnd()   >= tmpend) {
	found = (Fragment)frags.elementAt(i);
      }
    }
    
    // If we already have it then return the sequence
    if (found != null) {
      //return;
    }
    
    // If not generate a list of Fragments we need to get
    Vector newfrags = findFrags(tmpstart,tmpend);
    
    // Fetch fragments
    for (int i = 0; i < newfrags.size(); i++) {
      Fragment f = (Fragment)newfrags.elementAt(i);
      //System.out.println("New frag " + f.getStart() + " " + f.getEnd());
      frags.addElement(f);      
      fetchFragment((Fragment)newfrags.elementAt(i));

    }
    
  }

  public void fetchFragment(Fragment f) {
    //System.out.println("Fetching fragment " + f.getStart() + " " + f.getEnd() + " " + f.getFeatures());
    
    // This needs to change if we want more than repeats (which indeed we do)
    GetFeatureThread r = new GetFeatureThread(getName(),String.valueOf(f.getStart() + getStart() - 1),String.valueOf(f.getEnd() + getStart() - 1),this,false,true,false);
    r.start();
    
    r.setFragment(f);
    
    if (threads == null) {
      threads = new Vector();
    }
    
    threads.addElement(r);
  }

  public Vector findFrags(int start, int end) {

    // If we have no frags then we just create a fresh one
    Vector newFrags = new Vector();
    
    if (frags.size() == 0) {
      Fragment f = new Fragment(start,end,"");
      newFrags.addElement(f);
      //System.out.println("Initializing frags");
      return newFrags;
    }
    
    // Sort the fragments by start coord (none should overlap)
    
    Collections.sort(frags,new FragmentStartComparer());
    
    // Check whether the gaps overlap the region
    
    Fragment prev = null;
    
	// Check initial gap

	for (int i = 0; i < frags.size(); i++) {
	    Fragment f1 = (Fragment)frags.elementAt(i);
	    //Initial gap
	    if (i == 0) {
		int tmpstart = 1;
		int tmpend   = f1.getStart()-1;

		if (!(tmpstart > end ||
		      tmpend   < start)) {

		    if (start < tmpstart) {
			start = tmpstart;
		    }
		    if (end > tmpend) {
			end  = tmpend;
		    }

		    Fragment f = new Fragment(start,end,"");
		    newFrags.addElement(f);
		    //System.out.println("Adding start gap " + start + " " + end);
		}
	    }
	    // Middle gaps
	    if (i > 0) {

		int tmpstart = prev.getEnd()+1;
		int tmpend   = ((Fragment)frags.elementAt(i)).getStart()-1;
		
		//System.out.println("tmpstart/end " + tmpstart + " " + tmpend);

		if(tmpend >= tmpstart) {
		    if (!(tmpstart > end ||
			  tmpend   < start)) {
			
			if (start < tmpstart) {
			    start = tmpstart;
			}
			if (end > tmpend) {
			    end = tmpend;
			}
			Fragment f = new Fragment(start,end,"");
			newFrags.addElement(f);
			//System.out.println("Adding middle gap " + start + " " + end);
		    }
		}
	    }

	    // End gap

	    if (i == frags.size()-1) {
		int tmpstart = f1.getEnd()+1;
		int tmpend   = getEnd();

		if (!(tmpstart > end ||
		      tmpend   < start)) {

		    if (start < tmpstart) {
			start = tmpstart;
		    }
		    if (end > tmpend) {
			end = tmpend;
		    }
			
		    Fragment f = new Fragment(start,end,"");
		    newFrags.addElement(f);
		    //System.out.println("Adding end gap " + start + " " + end);
		}

	    }

	    prev = (Fragment)frags.elementAt(i);
	}

	//return the new frags

	return newFrags;
    }

    public void printFrags() {
      System.out.println("\n*****");

	for (int i = 0; i < frags.size(); i++) {
	    Fragment f = (Fragment)frags.elementAt(i);

	    System.out.println(" - " + f.getStart() + " " + f.getEnd() + " " + (f.getEnd()-f.getStart()+1));
	}
	System.out.println("\n*****\n");
    }

  public Vector overlaps(int start, int end) {
    Vector  out   = new Vector();

    boolean found = false;

    for (int i = 0; i < frags.size(); i++) {
      Fragment f = (Fragment)frags.elementAt(i);

      //System.out.println("in overlap " + f + " " + f.hasFeatures);

      if (f.hasFeatures == true) {
	//	System.out.println("Size is " + f.getFeatures().size());
      }
	
      //System.out.println("End " + f.getEnd() + " " + end);
      //System.out.println("Start " + f.getStart() + " " + start);

      if (!(f.getEnd()   < start||
	    f.getStart() > end)) {

	if (f.hasFeatures == true) {
	  found = true;

	  for (int ii = 0; ii < f.getFeatures().size(); ii++) {
	    
	    SequenceFeature sf = (SequenceFeature)f.getFeatures().elementAt(ii);
	    if (ii == 0) {
	      //System.out.println("Start " + sf.getStart() + " " + sf.getEnd());
	    }
	    if (!(sf.getStart() > end ||
		  sf.getEnd() < start)) {
	      
	      out.addElement(sf);


	    }
	  }
	}
      }
    }
    
    if (found == true) {
      return out;
    }
    

    // Fetch a biggish piece here
    
    start = start - 1000000;
    if (start < 1) {start = 1;}
    
    end   = end + 1000000;
    if (end > getEnd()) {end = getEnd();}
    
    //System.out.println("\n\nGetting overlap region " + start + " " + end);
    
    getFeatureRegion(start,end);
    
    //printFrags();
    
    return out;
  }

    public void actionPerformed(ActionEvent e) {
	if (e.getActionCommand().equals("Done")) {

	    for (int ii = 0; ii < threads.size(); ii++) {
		GetFeatureThread t = (GetFeatureThread)threads.elementAt(ii);


		if (e.getSource() == t) {
		  Fragment         f = t.getFragment();	 // This fills up the strings
		  System.out.println("****** Finished GFF thread " + f + " " + f.hasFeatures + " " + f.getStart() + " " + f.getEnd() + " " + f.getFeatures().size());
		  threads.removeElement(t);
		 
		  for (int i = 0; i < f.getFeatures().size(); i++) {
		    SequenceFeature sf = (SequenceFeature)f.getFeatures().elementAt(i);
		    //System.out.println(" - " + sf.getStart() + " " + sf.getEnd());
		  }
		  //	  System.out.println("Controller " + c);
		  if (c != null) {
		    // if (!(av.getStartRes() > t.getFragment().getEnd() ||
		    //av.getEndRes()   < t.getFragment().getStart())) {
		    //System.out.println("Redrawing screen");
		    // Only need to redraw if the features are on the screen!!!
		    // Doesn't explain the top panel though!
		    c.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.COLOURING));
		    
		    //}
		  }
		}
	    }
	    
	}
    }

}











